﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.Xml;
using System.Collections;

namespace NMoq.Core
{
    public class Serializer
    {
        /// <summary>
        /// if target can be serialized , return serialized value
        /// otherwise return HashCode value
        /// </summary>
        /// <param name="targetType"></param>
        /// <param name="target"></param>
        /// <returns></returns>
        public static string Serialize(object target)
        {
            Type targetType = target.GetType();
            if (!BeSerializable(targetType))
                return target.GetHashCode().ToString();

            StringBuilder strBuilder = new StringBuilder();
            using (XmlWriter xmlWriter = XmlWriter.Create(strBuilder))
            {
                XmlSerializer xmlSer = new XmlSerializer(targetType);
                xmlSer.Serialize(xmlWriter, target);
                xmlWriter.Flush();
                xmlWriter.Close();
            }
            return strBuilder.ToString();
        }

        /// <summary>
        /// if serializedValue can be deserialized ,return serialized object
        /// otherwise throw exception
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="serializedValue"></param>
        /// <returns></returns>
        public static T Deserialize<T>(string serializedValue)
        {
            object target = Deserialize(typeof (T),serializedValue );
            return target!=null ?(T)target: default (T); 
        }

        /// <summary>
        /// if serializedValue can be deserialized ,return serialized object
        /// otherwise throw exception
        /// </summary>
        /// <param name="targetType"></param>
        /// <param name="serializedValue"></param>
        /// <returns></returns>
        public static object Deserialize(Type targetType, string serializedValue)
        {
            if (BeSerializable(targetType))
                throw new InvalidOperationException("The targetType can't be serialized!");

            object target = null;
            using (XmlReader xmlReader = XmlReader.Create(serializedValue))
            {
                XmlSerializer xmlSer = new XmlSerializer(targetType);
                target = xmlSer.Deserialize(xmlReader);
                xmlReader.Close();
            }
            return target;
        }

        /// <summary>
        /// Is the targetType can be serialized ,
        /// if the targetType have a class attribute: SerializeAttribute 
        /// it can be serialized
        /// </summary>
        /// <param name="targetType"></param>
        /// <returns></returns>
        public static bool BeSerializable(Type targetType)
        {
            object[] allAttrs = targetType.GetCustomAttributes(typeof(SerializableAttribute),false );
            return  allAttrs.Length > 0 && (allAttrs[0] as SerializableAttribute) != null;
        }
    }
}
